home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-08-28 | 19.4 KB | 474 lines | [TEXT/MPS ] |
- /*
- File: CMHndOps.c
-
- Contains: Container Manager Handler Operations
-
- Written by: Ira L. Ruben
-
- Owned by: Ed Lai
-
- Copyright: © 1991 - 1996 by Apple Computer, Inc., all rights reserved.
-
- Change History (most recent first):
-
- <3> 8/13/96 DM 1362809: disable containers on error
- <2> 1/15/96 TJ Cleaned Up
- <2> 8/26/94 EL #1181622 Ownership update.
- <1> 2/3/94 EL first checked in
-
- To Do:
- */
-
- /*---------------------------------------------------------------------------*
- | |
- | <<< CMHndOps.c >>> |
- | |
- | Container Manager Handler Operations |
- | |
- | Ira L. Ruben |
- | 12/05/91 |
- | |
- | Copyright Apple Computer, Inc. 1991-1994 |
- | All rights reserved. |
- | |
- *---------------------------------------------------------------------------*
-
- Containers are always access through handlers, to provide platform independence. Handlers
- are responsible for doing all the I/O operations, including opening and closing, to
- containers. They are also responsible for reading and writing the container label.
-
- The routines in this file are the API interfaces to allow the Container Manager to
- determine what handlers it should use for a particular container. The Container Manager
- handler routines defined here maintain container type name/metahandler associations.
-
- A metahandler is a special required routine the API user defines which is called by the
- API to return the address of the handler I/O routines that the Container Manager needs.
- There following handlers are needed by the API. They should have these prototypes:
-
- void open_Handler(CMRefCon refCon, CMOpenMode mode);
- void close_Handler(CMRefCon refCon);
- CMSize flush_Handler(CMRefCon refCon);
- CMSize seek_Handler(CMRefCon refCon, CM_LONG posOff, CMSeekMode mode);
- CMSize tell_Handler(CMRefCon refCon);
- CMSize read_Handler(CMRefCon refCon, CMPtr buffer, CMSize elementSize, CMCount theCount);
- CMSize write_Handler(CMRefCon refCon, CMPtr buffer, CMSize elementSize, CMCount theCount);
- CMEofStatus eof_Handler(CMRefCon refCon);
- CMBoolean trunc_Handler(CMRefCon refCon, CMSize containerSize);
- CMSize containerSize_Handler(CMRefCon refCon);
- void readLabel_Handler(CMRefCon refCon, CMMagicBytes magicByteSequence,
- CMContainerFlags *flags, CM_USHORT *bufSize,
- CM_USHORT *majorVersion, USHORT *minorVersion,
- CMSize *tocOffset, CMSize *tocSize);
- void writeLabel_Handler(CMRefCon refCon, CMMagicBytes magicByteSequence,
- CMContainerFlags flags, CM_USHORT bufSize,
- CM_USHORT majorVersion, USHORT minorVersion,
- CMSize tocOffset, CMSize tocSize);
- CMValue returnParentValue_Handler(CMRefCon refCon);
- CM_UCHAR *returnContainerName_Handler(CMRefCon refCon);
- CMType returnTargetType_Handler(CMRefCon refCon, CMContainer container);
- void extractData_Handler(CMRefCon refCon, CMDataBuffer buffer,
- CMSize size, CMPrivateData data);
- void formatData_Handler(CMRefCon refCon, CMDataBuffer buffer,
- CMSize size, CMPrivateData data);
-
- The names chosen can be, of course, anything. They were chosen here to document what
- each routine does since the semantics for each routine follow exactly those of standard
- ANSI C. The last two routines are for reading and writing labels. See documentation of
- those routines for further details. Note, we will talk about the "refCon" a little later.
-
- Not all of the above handlers are required at all times. Some are obviously used only
- for input and others for output. Here is a chart as to which routines are required for
- reading, writing, and updating:
-
- Mode
- Reading | Writing | Updating
- ---------+-----------+---------
- open X | X | X
- close X | X | X
- flush | |
- seek X | X | X
- tell X | X | X
- read X | | X
- write | X | X
- eof | |
- trunc | |
- size X | X | X
- readLabel X | | X
- writeLabel | X | X
- parent 1 | 1 |
- name | |
- targetType | | X
- extract X | X | X
- format X | X | X
- ---------+-----------+---------
-
- Notes: 1. The parent value handler is required ONLY for embedded container handlers.
-
- The X's indicate required for the mode. Blanks mean optional or are not used for the
- mode. Note, that updating generally is an or'ing of the reading and writing cases.
-
- In each handler routine a "refCon" is passed. This is short for "reference constant". It
- is an arbitrary (void *) value that is passed to the Container Manager when a container
- is to be opened. The Container Manager doesn't look at it. It simply passes it on each
- handler call. The intent is that it will be used as a communication device to allow the
- handler routines to coordinate among themselves.
- */
-
-
- #include <stddef.h>
- #include <string.h>
- #include <stdarg.h>
- #include <stdio.h>
-
- #ifndef __CMVERSION__
- #include "CMVers.h"
- #endif
- #ifndef __CMTYPES__
- #include "CMTypes.h"
- #endif
- #ifndef __CM_API__
- #include "CMAPI.h"
- #endif
- #ifndef __LISTMGR__
- #include "ListMgr.h"
- #endif
- #ifndef __TOCENTRIES__
- #include "TOCEnts.h"
- #endif
- #ifndef __TOCOBJECTS__
- #include "TOCObjs.h"
- #endif
- #ifndef __GLOBALNAMES__
- #include "GlbNames.h"
- #endif
- #ifndef __CONTAINEROPS__
- #include "Containr.h"
- #endif
- #ifndef __HANDLERS__
- #include "Handlers.h"
- #endif
- #ifndef __SESSIONDATA__
- #include "Session.h"
- #endif
- #ifndef __ERRORRPT__
- #include "ErrorRpt.h"
- #endif
- #ifndef __UTILITYROUTINES__
- #include "Utility.h"
- #endif
-
- CM_CFUNCTIONS
-
- /* The following generates a segment directive for Mac only due to 32K Jump Table */
- /* Limitations. If you don't know what I'm talking about don't worry about it. The */
- /* default is not to generate the pragma. Theoritically unknown pragmas in ANSI won't */
- /* choke compilers that don't recognize them. */
-
- #if CM_MPW
- #pragma segment CMHandlerOps
- #endif
-
-
- struct GetOpComArea { /* CMGetOperation() object walking comm area layout: */
- TOCValuePtr theValue; /* the first (should be only) global name value */
- CM_USHORT nbrOfGlobalNames;/* count of nbr of global names found in object */
- };
- typedef struct GetOpComArea GetOpComArea, *GetOpComAreaPtr;
-
-
- /*-----------------------------------------------------------------------*
- | CMSetMetaHandler - associate a container type name with a metahandler |
- *-----------------------------------------------------------------------*
-
- This routine records the association of type names with their metahandlers. A type name
- is passed to CMOpen[New]Container() so that the Container Manager can use it to call the
- appropriate metahandler to get the actual handler addresses. Further, a value that has
- a global type name which has an associated metahandler will produce a "dynamic" value.
-
- The function returns the address of the previous metahandler for the specified type if
- one exists. Otherwise NULL is returned.
-
- Note, that type name/metahandler associations are global to all containers. Therefore,
- the Container Manager neest to store its information as a function of the current session
- global data defined by CMStartSession(). Hence the sessionData pointer should always be
- the value returned by CMStartSession().
- */
-
- CMHandlerAddr CM_FIXEDARGS CMSetMetaHandler(CMconst_CMSession sessionData,
- CMconst_CMGlobalName typeName,
- CMMetaHandler metaHandler)
- {
- Boolean dup;
- CMMetaHandler prevMetaHandler;
- MetaHandlerPtr h;
-
- if (sessionData == NULL) return (NULL); /* NOP if not initialized! */
-
- /* Enter the new metahandler and its type name into the metaHandler symbol table. The */
- /* address of the new entry is returned. If there is one already there, the address */
- /* of that is returned, dup is set true, and nothing else done. */
-
- h = cmDefineMetaHandler(metaHandler, (CM_UCHAR *)typeName, &dup,
- (SessionGlobalDataPtr)sessionData);
-
- if (!h) { /* if allocation failed... */
- SessionERROR1(CM_err_NoHandler, typeName);/* yell and do nothing else */
- return (NULL); /* ...that's what I said! */
- }
-
- /* If there was a previous entry, update it with the new metahandler address and */
- /* return the "old" address. */
-
- if (dup) { /* if dup entry... */
- prevMetaHandler = h->metaHandler; /* ...we will return "old" metahandler */
- h->metaHandler = metaHandler; /* ...just replace with new metahandler */
- } else
- prevMetaHandler = NULL; /* if not dup, there is no prev. handler */
-
- return ((CMHandlerAddr)prevMetaHandler);
- }
-
-
- /*-------------------------------------------------------------------------------*
- | CMGetMetaHandler - return the metahandler address associated with a type name |
- *-------------------------------------------------------------------------------*
-
- This function searches the metaHandler symbol table for the specified typeName and returns
- the associated metahandler address. NULL is returned if the type name does not exist.
-
- As with CMSetMetaHandler() above, CMGetMetaHandler() requires the session global data
- pointer returned by CMStartSession().
- */
-
- CMHandlerAddr CM_FIXEDARGS CMGetMetaHandler(CMconst_CMSession sessionData,
- CMconst_CMGlobalName typeName)
- {
- MetaHandlerPtr h;
-
- if (sessionData == NULL) return (NULL); /* NOP if not initialized! */
-
- h = cmLookupMetaHandler((CM_UCHAR *)typeName, (SessionGlobalDataPtr)sessionData);
-
- if (!((SessionGlobalDataPtr)sessionData)->success) {/* if we had allocation error... */
- SessionERROR1(CM_err_HandlerError, typeName); /* ...yell */
- h = NULL;
- }
-
- return (h ? (CMHandlerAddr)h->metaHandler : NULL); /* NULL or found metahandler */
- }
-
-
- /*---------------------------------------------------------*
- | checkValue - check a value to see if it's a global name |
- *---------------------------------------------------------*
-
- This is a cmWalkObject() action routine initiated by CMGetOperation() below to find the
- global name value in an object. The "refCon" is a pointer to a GetOpComArea communication
- area where we will save the value pointer. We also count the number of global names
- seen in the object. It shoould be 1. But we walk the entire object just to be sure.
-
- Note, this "static" is intentionally left to default memory model under DOS since it is
- passed as a function pointer to cmWalkObject().
- */
-
- static TOCWalkReturns checkValue(ContainerPtr container, TOCValuePtr theValue, CMRefCon refCon)
- {
- GetOpComAreaPtr g = (GetOpComAreaPtr)refCon;
- ContainerPtr unused = container;
-
- if (theValue->flags & kCMGlobalName) {
- g->theValue = theValue; /* save global name ptr */
- ++g->nbrOfGlobalNames; /* count it too */
- }
-
- return (WalkNextTOCValue); /* continue value walk */
- }
-
-
- /*--------------------------------------------------------------------------*
- | CMGetOperation - get handler for a specific operation on a specific type |
- *--------------------------------------------------------------------------*
-
- This routine takes a targetType which is defined as a globally unique name and uses that
- name find a metahandler. The matahandler, in turn, is used to get the handler routine
- address for the specified operationType. The function returns the resulting address.
-
- Metahandler proc addresses are given to the Container Manager by calls to
- CMSetMetaHandler(). The global name value for the input targetType is treated as the
- typeName to find the metahandler. As just mentioned above, the metahandler is called
- with the operationType to get the operation address returned.
- */
-
- CMHandlerAddr CM_FIXEDARGS CMGetOperation(CMType targetType,
- CMconst_CMGlobalName operationType)
- {
- TOCObjectPtr theObject;
- TOCValuePtr theValue;
- ContainerPtr container;
- CM_CHAR *typeName;
- MetaHandlerPtr metaHandler;
- GetOpComArea getOpComArea;
-
- ExitIfBadType(targetType, NULL); /* validate targetType */
-
- theObject = (TOCObjectPtr)targetType;
- container = theObject->container;
-
- /* Walk the entire object and look at all the values to find the value for a global */
- /* name. The object can have other properties and values, but there better be only */
- /* one global name. The object is walked with cmWalkObject(). The "refCon" we pass */
- /* is a pointer to a communication area which will hold the count of the global name */
- /* values and the pointer to it. As just mentioned, if the count comes back other */
- /* than 1, we have an error. */
-
- getOpComArea.theValue = NULL; /* init value ptr to no value yet */
- getOpComArea.nbrOfGlobalNames = 0; /* there are no global names yet too*/
-
- cmWalkObject(container, theObject, &getOpComArea, NULL, NULL, NULL, checkValue);
-
- /* Get the global name for this type. The type must have only one property, one value,*/
- /* and that value must be for a global name. */
-
- if (getOpComArea.nbrOfGlobalNames > 1) { /* must have exactly 1 global name */
- Container_Disable(container);
- ERROR2(CM_err_AmbiguousType, "CMGetOperation", CONTAINERNAME);
- return (NULL);
- }
-
- if (getOpComArea.nbrOfGlobalNames == 0) {
- Container_Disable(container);
- ERROR2(CM_err_TypeNotGlobal, "CMGetOperation", CONTAINERNAME);
- return (NULL);
- }
-
- /* Set the typeName to point at the global name now that we're happy there is one... */
-
- theValue = getOpComArea.theValue;
- if (theValue == NULL) return (NULL); /* safety */
- typeName = GetGlobalName(theValue->value.globalName.globalNameSymbol);
-
- /* Use the global name to look up the metahandler in the meta handler symbol table. */
- /* A few things can go wrong here, but if we successfully found a metahandler symbol */
- /* table entry we use the resulting metahandler proc pointer to get the routine */
- /* address for the input operationType. That's what we return. */
-
- if ((metaHandler = cmLookupMetaHandler((CM_UCHAR *)typeName, SESSION)) == NULL) {
- Container_Disable(container);
- ERROR1(CM_err_UndefMetaHandler, typeName);
- return (NULL);
- }
-
- if (!SessionSuccess) { /* if allocation error... */
- Container_Disable(container);
- ERROR1(CM_err_HandlerError, typeName); /* ...yell */
- return (NULL);
- }
-
- return ((CMHandlerAddr)(*metaHandler->metaHandler)(NULL, operationType));
- }
-
-
- /*---------------------------------------------------------------------------*
- | CMMalloc - handler/user interface to Container Manager's memory allocator |
- *---------------------------------------------------------------------------*
-
- This routine provides a access path for the user (usually a handler writer) to use the
- same memory management allocator defined for the current Container Manager session. size
- bytes are allocated as defined by that handler.
-
- The session memory allocator handler is defined by the metahandler passed to
- CMStartSession(). The sessionData is the current session refNum returned from
- CMStartSession().
- */
-
- void CM_PTR * CM_FIXEDARGS CMMalloc(CMSize size, CMSession sessionData)
- {
- return ((sessionData == NULL) ? NULL : SessionMalloc(size));
- }
-
-
- /*---------------------------------------------------------------------------*
- | CMFree - handler/user interface to Container Manager's memory deallocator |
- *---------------------------------------------------------------------------*
-
- This routine provides a access path for the user (usually a handler writer) to use the
- same memory management deallocator defined for the current Container Manager session. A
- pointer (ptr) assumed to be allocated by CMMalloc() is passed to release the memory in the
- manner defined by the handler.
-
- The session memory deallocator handler is defined by the metahandler passed to
- CMStartSession(). The sessionData is the current session refNum returned from
- CMStartSession().
- */
-
- void CM_FIXEDARGS CMFree(CMPtr ptr, CMSession sessionData)
- {
- if (sessionData != NULL) SessionFree(ptr);
- }
-
-
- /*--------------------------------------------------------------------------------*
- | CMError - handler/user interface to Container Manager's session error reporter |
- *--------------------------------------------------------------------------------*
-
- This routines provides an access path for the user (usually an handler writer) to use the
- same error reporter defined for the current Container Manager session. The session error
- reporting handler is defined by the metahandler passed to CMStartSession(). The
- sessionData is the current session refNum returned from CMStartSession(). The string is
- the message to be processed by the handler. Optional string inserts can be passed to put
- into the string. The string indicates the position of the inserts by "^0", "^1", etc.
- "^0" gets the first insert, "^1" the second, and so on. Inserts may be repeated.
-
- Note, the maximum length of the passed message plus its inserts is limited to 256
- characters. Also, if the error reporting handler returns, so with this routine.
- */
-
- void CM_VARARGS CMError(CMSession sessionData, CMErrorString message, ...)
- {
- va_list inserts;
-
- va_start(inserts, message);
- CMVError(sessionData, message, inserts);
- va_end(inserts);
- }
-
-
- /*---------------------------------------------------------------------------------*
- | CMVError - handler/user interface to Container Manager's session error reporter |
- *---------------------------------------------------------------------------------*
-
- This routine is the same as CMError() above, except that the extra message inserts are
- given as a variable argument list as defined by the "stdarg" facility.
-
- This routine assumes the caller sets up and terminates the variable arg list using the
- "stdarg.h" calls as follows:
-
- #include <stdarg.h>
-
- callersRoutine(args, ...)
- {
- va_list inserts;
-
- - - -
-
- va_start(inserts, args);
- CMVError(sessionData, message, inserts);
- va_end(inserts);
-
- - - -
- }
-
- See CMError() for further details.
- */
-
- void CM_FIXEDARGS CMVError(CMSession sessionData, CMErrorString message, va_list inserts)
- {
- if (sessionData != NULL) { /* if session defined...*/
- strcpy((CM_CHAR *)SessionScratchBufr, message); /* ...use private bufr */
- CMVAddMsgInserts((CM_CHAR *)SessionScratchBufr, 256, inserts); /* ...add in inserts */
- SessionERROR1(CM_err_GenericMessage, SessionScratchBufr); /* ...report error */
- }
- }
-
- CM_END_CFUNCTIONS
-